import constValue from './const';
import { clockFactory } from './utils';
import config from './config';
export const dayArr = ['日', '一', '二', '三', '四', '五', '六'];

/**
 * 日期信息的操作类
 */
class DateClass {
    getWeek(week: number) {
        return `周${dayArr[week]}`;
    }
    getCurrent() {
        const date = new Date();
        return [date.getFullYear(), date.getMonth() + 1, date.getDate()];
    }
    changeTimeStr(time: string) {
        return time.split('-').map((el) => Number(el));
    }
    getCurrentStr(isZero: boolean = false) {
        const date = new Date();
        return isZero
            ? date.getFullYear() +
                  '-' +
                  clockFactory(date.getMonth() + 1) +
                  '-' +
                  clockFactory(date.getDate())
            : date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate();
    }
    getHolidays(date: number[]) {
        return (
            config.Holidays.indexOf(`${date[0]}${clockFactory(date[1])}${clockFactory(date[2])}`) >
            -1
        );
    }
    /**
     * 获取公历月份天数
     * @param {number} y 年
     * @param {number} m 月
     * @returns {number} 返回输入月份天数
     */
    solarMonth(y: number, m: number, d?: number) {
        if (m == 2) return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0 ? 29 : 28;
        return constValue.solarMonth[m - 1];
    }
    /**
     * 获得当前月份第一天是星期几
     * @param {number} y 年
     * @param {number} m 月
     * @returns {number} 返回星期数字[0-6]
     */
    solarWeeks(y: number, m: number) {
        return this.solarWeek(y, m, 1);
    }
    /**
     * 获取公历某一天是星期几
     * @param {number} y 年
     * @param {number} m 月
     * @param {number} d 日
     * @returns {number} 返回星期数字[0-6]
     */
    solarWeek(y: number, m: number, d: number) {
        let date = new Date(y, m - 1, d);
        let week = date.getDay();
        return week;
    }
    /**
     * 返回农历月份通俗表示法
     * @param {number} m 农历月
     * @returns {string} 返回农历月份通俗表示法：'正月'
     */
    toChinaMonth(m: number) {
        let r = String(m).slice(0, 1) == '0';
        return r
            ? '\u95f0' + constValue.nStr3[m - 1] + '\u6708'
            : constValue.nStr3[m - 1] + '\u6708'; // 加上"月"字
    }
    /**
     * 返回农历日期通俗表示法
     * @param {number} d 农历日
     * @returns {string} 返回农历日期通俗表示法：‘初一’
     */
    toChinaDay(d: number) {
        let str = d == 10 ? constValue.nStr2[0] : constValue.nStr2[Math.floor(d / 10)];
        return str + (d % 10 ? constValue.nStr1[d % 10] : constValue.nStr1[10]);
    }
    /**
     * 农历年份转生肖
     * @param {number} y 农历年
     * @returns {string} 农历年份转生肖
     */
    getAnimal(y: number) {
        return constValue.Animals[(y - 4) % 12];
    }
    /**
     * 返回公历日期所属星座
     * @param {number} m 月
     * @param {number} d 日
     * @returns {string} 返回星座信息
     */
    toAstro(y: number, m: number, d: number) {
        let s =
            '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf';
        let arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22];
        let i = m * 2 - (d < arr[m - 1] ? 2 : 0);
        return s.slice(i, i + 2) + '\u5ea7';
    }
    /**
     * 根据公历日期返回农历日期
     * @param {number} y 年
     * @param {number} m 月
     * @param {number} d 日
     * @returns {string} 返回农历日期,如果是闰月则月份前含0
     */
    getLunars(y: number, m: number, d: number) {
        let date = new Date(y, m - 1, d),
            i,
            leap = 0,
            temp = 0;
        let offset = (Date.UTC(y, m - 1, d) - Date.UTC(1900, 0, 31)) / 86400000;
        for (i = 1900; i < 2101 && offset > 0; i++) {
            temp = this.lYearDays(i);
            offset -= temp;
        }
        if (offset < 0) {
            offset += temp;
            i--;
        }
        // 获取闰月
        let year = i;
        leap = this.leapMonth(i);
        let isLeap = false;
        // 校验闰月
        for (i = 1; i < 13 && offset > 0; i++) {
            if (leap > 0 && i == leap + 1 && !isLeap) {
                --i;
                isLeap = true;
                temp = this.leapDays(year); // 闰月天数
            } else {
                temp = this.monthDays(year, i); // 普通月天数
            }
            if (isLeap && i == leap + 1) isLeap = false;
            offset -= temp;
        }
        if (offset == 0 && leap > 0 && i == leap + 1) {
            if (isLeap) {
                isLeap = false;
            } else {
                isLeap = true;
                --i;
            }
        }
        if (offset < 0) {
            offset += temp;
            --i;
        }
        // 农历月
        let month = isLeap ? '0' + i : i;
        // 农历日
        let day = ++offset;
        return year + '-' + month + '-' + day;
    }
    /**
     * 返回农历年闰月，没有闰月则返回0
     * @param {number} y 农历年
     * @returns {number} 农历年闰月月份数字，没有闰月则返回0
     */
    leapMonth(y: number, m?: number, d?: number) {
        return constValue.lunarInfo[y - 1900] & 0xf;
    }
    /**
     * 返回农历年闰月的天数，没有闰月则返回0
     * @param {number} y 农历年
     * @returns {number} 闰月的天数，没有闰月则返回0
     */
    leapDays(y: number, m?: number, d?: number) {
        return this.leapMonth(y, m, d) ? (constValue.lunarInfo[y - 1900] & 0x10000 ? 30 : 29) : 0;
    }
    /**
     * 查询公历日期节日
     * @param {number} m 月
     * @param {number} d 日
     * @returns {string | boolean} 返回节日信息，不是节日则返回false
     */
    getSolarDay(m: number, d: number) {
        let solarDay: false | string = false;
        for (let i = 0; i < constValue.sFtv.length; i++) {
            if (
                parseInt(constValue.sFtv[i].slice(0, 2)) == m &&
                parseInt(constValue.sFtv[i].slice(2, 4)) == d
            ) {
                solarDay = constValue.sFtv[i].slice(5);
            }
        }
        return solarDay;
    }
    /**
     * 通过农历日期获取农历节日
     * @param {number} y 农历年
     * @param {number|string} m 农历月，如果是闰月则为字符串‘07’
     * @param {number} d 农历日
     * @returns {string|false} 返回农历节日，没有节日则返回false
     */
    getlunarDay(y: number, m: number, d: number) {
        if (String(m).slice(0, 1) == '0') return false; //如果是闰月则没有节日
        let lunarDay: false | string = false;
        for (let i = 0; i < constValue.lFtv.length; i++) {
            if (
                parseInt(constValue.lFtv[i].slice(0, 2)) == m &&
                parseInt(constValue.lFtv[i].slice(2, 4)) == d
            ) {
                lunarDay = constValue.lFtv[i].slice(5);
            }
        }
        // 判断是否为除夕
        if (m == 12 && this.monthDays(y, m, d) == d) lunarDay = '除夕';
        return lunarDay;
    }
    /**
     * 返回农历一年的天数
     * @param {number} y 农历年份
     * @returns {number} 一年的天数
     */
    lYearDays(y: number, m?: number, d?: number) {
        let i,
            sum = 348;
        for (i = 0x8000; i > 0x8; i >>= 1) {
            sum += constValue.lunarInfo[y - 1900] & i ? 1 : 0;
        }
        return sum + this.leapDays(y);
    }
    /**
     * 获取农历非闰月的总天数
     * @param {number} y 农历年
     * @param {number} m 农历月
     * @returns {number} 返回农历非闰月的天数
     */
    monthDays(y: number, m: number, d?: number) {
        return constValue.lunarInfo[y - 1900] & (0x10000 >> m) ? 30 : 29;
    }
    /**
     * 获取公历年第n个节气日期
     * @param {number} y 年
     * @param {number} n 第几个节气
     * @returns {string} 返回日期,0506
     */
    getTerm(y: number, n: number) {
        let _table = constValue.sTermInfo[y - 1900];
        let _info = [
            parseInt('0x' + _table.slice(0, 5)).toString(),
            parseInt('0x' + _table.slice(5, 10)).toString(),
            parseInt('0x' + _table.slice(10, 15)).toString(),
            parseInt('0x' + _table.slice(15, 20)).toString(),
            parseInt('0x' + _table.slice(20, 25)).toString(),
            parseInt('0x' + _table.slice(25)).toString()
        ];
        let d = [
            _info[0].slice(0, 1),
            _info[0].slice(1, 3),
            _info[0].slice(3, 4),
            _info[0].slice(4, 6),

            _info[1].slice(0, 1),
            _info[1].slice(1, 3),
            _info[1].slice(3, 4),
            _info[1].slice(4, 6),

            _info[2].slice(0, 1),
            _info[2].slice(1, 3),
            _info[2].slice(3, 4),
            _info[2].slice(4, 6),

            _info[3].slice(0, 1),
            _info[3].slice(1, 3),
            _info[3].slice(3, 4),
            _info[3].slice(4, 6),

            _info[4].slice(0, 1),
            _info[4].slice(1, 3),
            _info[4].slice(3, 4),
            _info[4].slice(4, 6),

            _info[5].slice(0, 1),
            _info[5].slice(1, 3),
            _info[5].slice(3, 4),
            _info[5].slice(4, 6)
        ];
        return d[n - 1];
    }
}

export default new DateClass();
